package core

import (
	"errors"
	"net"
	"net/tcpserver"
	"sync"
	l "util/log"
)

type client struct {
	address net.Addr
}

type ServSock struct {
	sock    *tcpserver.TcpServer
	clients map[int]*client
	lock    sync.Mutex
}

func (s *ServSock) OnCreate(ts *tcpserver.TcpServer) {
	s.sock = ts
}

func (s *ServSock) OnConnect(index int, serial int, addr net.Addr) {
	s.lock.Lock()
	defer s.lock.Unlock()
	c := &client{}
	c.address = addr
	if _, dup := s.clients[index]; dup {
		delete(s.clients, index)
	}

	s.clients[index] = c
	regionMgr.appClient.Status(s.sock.Count())
	l.TraceInfo("servsock", "client connected: ", addr.String())
}

func (s *ServSock) Addr() net.Addr {
	return s.sock.GetAddr()
}

func (s *ServSock) OnDisconnect(index int, serial int) {
	s.lock.Lock()
	defer s.lock.Unlock()

	if c, dup := s.clients[index]; dup {
		l.TraceInfo("servsock", "client closed: ", c.address.String())
		delete(s.clients, index)
	}

	regionMgr.appClient.Status(s.sock.Count() - 1)

}

func (s *ServSock) Recv(index int, serial int, data []byte, size int) {
	go handleMsg(index, serial, data, size)
}

func (s *ServSock) Close() {
	if s.sock != nil {
		s.sock.Close(true)
		s.sock = nil
		l.TraceInfo("servsock", "closed")
	}
}

func (s *ServSock) Start(threads int) error {
	if s.sock != nil {
		return s.sock.Start(threads)
	}

	return errors.New("socket not connected")
}

func CreateServSock(ip string, port int) *ServSock {
	ss := &ServSock{}
	ss.clients = make(map[int]*client)
	tcpserver.CreateTcpServer(ss, ip, port, 2048)

	return ss
}
